home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / login.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  34KB  |  1,071 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: login.c,v 1.184 2001/03/03 19:00:55 drscholl Exp $ */
  6.  
  7. #include <stdio.h>
  8. #include <time.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <ctype.h>
  12. #include "opennap.h"
  13. #include "hashlist.h"
  14. #include "debug.h"
  15.  
  16. int
  17. invalid_nick (const char *s)
  18. {
  19.     int     count = 0;
  20.     LIST   *list;
  21.     server_auth_t *auth;
  22.  
  23.     /* don't allow anyone to ever have this nick */
  24.     if (!strcasecmp (s, "operserv") || !strcasecmp (s, "chanserv") ||
  25.         !strcasecmp (s, "operator") || !strcasecmp (s, "nickserv"))
  26.         return 1;
  27.     /* check to make sure a user isn't attempting to use an alias of one
  28.      * of our peer servers.  we don't need to check the full dns name because
  29.      * nicks already can't contain a period (.)
  30.      */
  31.     for (list = Server_Auth; list; list = list->next)
  32.     {
  33.         auth = list->data;
  34.         if (auth->alias && !strcasecmp (auth->alias, s))
  35.             return 1;
  36.     }
  37.     if (strchr ("#&:-", *s))
  38.         return 1;               /* nick can't begin with # or & (denotes a channel) */
  39.     while (*s)
  40.     {
  41.         if (*s < '!' || *s > '~' || strchr ("%$*?.!\",\\", *s))
  42.             return 1;
  43.         count++;
  44.         s++;
  45.     }
  46.     /* enforce min/max nick length */
  47.     return (count == 0 || (Max_Nick_Length > 0 && count > Max_Nick_Length));
  48. }
  49.  
  50. static void
  51. sync_reginfo (USERDB * db)
  52. {
  53.     log ("sync_reginfo(): sending registration info to peers");
  54.     pass_message_args (NULL, MSG_SERVER_REGINFO,
  55.                        ":%s %s %s %s %s %u 0", Server_Name,
  56.                        db->nick, db->password,
  57. #if EMAIL
  58.                        db->email,
  59. #else
  60.                        "unknown",
  61. #endif
  62.                        Levels[db->level], db->created);
  63. }
  64.  
  65. /* pass a KILL message back to the server where the login request came from.
  66.  * this is used to sync up when we can't parse the login message, so we
  67.  * have no choice but to kill the client.  note that this only gets passed
  68.  * back to the server the request came from.
  69.  */
  70. static void
  71. kill_client (CONNECTION * con, const char *user, const char *reason)
  72. {
  73.     send_cmd (con, MSG_CLIENT_KILL, ":%s %s \"%s\"", Server_Name, user,
  74.               reason);
  75.     notify_mods (KILLLOG_MODE, "Server %s killed %s: %s", Server_Name, user,
  76.                  reason);
  77. }
  78.  
  79. static void
  80. zap_local_user (CONNECTION * con, const char *reason)
  81. {
  82.     ASSERT (validate_connection (con));
  83.     ASSERT (ISUSER (con));
  84.     ASSERT (reason != NULL);
  85.  
  86.     /* TODO: there is a numeric for this somewhere */
  87.     send_cmd (con, MSG_SERVER_NOSUCH, "You were killed by server %s: %s",
  88.               Server_Name, reason);
  89.     send_cmd (con, MSG_SERVER_DISCONNECTING, "0");
  90.     con->killed = 1;            /* dont generate a QUIT message */
  91.     remove_user (con);
  92.     /* avoid free'g con->user in remove_connection().  do
  93.        this here to avoid the ASSERT() in remove_user() */
  94.     con->class = CLASS_UNKNOWN;
  95.     con->uopt = 0;              /* just to be safe since it was free'd */
  96.     con->user = 0;
  97.     destroy_connection (con);
  98. }
  99.  
  100. /* if the server is full, try to find the client connected to the server
  101.  * the longest that isn't sharing any files.  expell that client to make
  102.  * room for other (possibly sharing) clients.
  103.  */
  104. static int
  105. eject_client (CONNECTION * con)
  106. {
  107.     int     i, loser = -1, leech = 0;
  108.     time_t  when = global.current_time;
  109.  
  110.     for (i = 0; i < global.clients_num; i++)
  111.     {
  112.         if (ISUSER (global.clients[i]) && global.clients[i] != con &&
  113.                 !global.clients[i]->killed && /* skip already killed clients */
  114.             (global.clients[i]->user->level == LEVEL_LEECH ||
  115.              (global.clients[i]->user->level == LEVEL_USER &&
  116.               global.clients[i]->user->sharing == 0)))
  117.         {
  118.             /* if we already found a leech, don't boot a LEVEL_USER even
  119.              * if the leech logged in more recently or is sharing files
  120.              */
  121.             if (leech && global.clients[i]->user->level > LEVEL_LEECH)
  122.                 continue;
  123.  
  124.             if (global.clients[i]->user->connected < when)
  125.             {
  126.                 loser = i;
  127.                 when = global.clients[i]->user->connected;
  128.                 if (global.clients[i]->user->level == LEVEL_LEECH)
  129.                     leech = 1;
  130.             }
  131.         }
  132.     }
  133.     if (loser == -1)
  134.         return 0;               /* no client to eject, reject current login */
  135.     /* pass NULL as the CONNECTION so we send the KILL back to the server
  136.      * where this user came from.  this is ok since the KILL is originating
  137.      * here and not being routed.
  138.      */
  139.     kill_user_internal (NULL, global.clients[loser]->user, Server_Name, 0,
  140.                         "server full, not sharing");
  141.     return 1;                   /* ok for current login to proceed despite being full */
  142. }
  143.  
  144. /* find the server name in the cache, or add it if it doesn't yet exist.
  145.  * this allows one copy of the server name in memory rather than copying it
  146.  * 1000 times for each user
  147.  */
  148. static char *
  149. find_server (char *s)
  150. {
  151.     LIST   *list;
  152.  
  153.     for (list = Server_Names; list; list = list->next)
  154.     {
  155.         if (!strcasecmp (s, list->data))
  156.             return list->data;
  157.     }
  158.     /* not found yet, allocate */
  159.     list = CALLOC (1, sizeof (LIST));
  160.     list->data = STRDUP (s);
  161.     list->next = Server_Names;
  162.     Server_Names = list;
  163.     return list->data;
  164. }
  165.  
  166. /* 2 <nick> <pass> <port> <client-info> <speed> [email] [build]
  167.  
  168.    servers append some additional information that they need to share in
  169.    order to link:
  170.  
  171.    2 <nick> <pass> <port> <client-info> <speed> <email> <ts> <ip> <server> <serverport>
  172.  
  173.    <ts> is the time at which the client logged in (timestamp)
  174.    <ip> is the client's ip address
  175.    <server> is the server they are connected to
  176.    <port> is the remote port on the server they are connected to */
  177. HANDLER (login)
  178. {
  179.     char   *av[10];
  180.     USER   *user;
  181.     LIST   *list;
  182.     int     ac, speed, port;
  183.     USERDB *db = 0;
  184.     unsigned int ip;
  185.     char   *host, realhost[256];
  186.     hashlist_t *clientinfo;
  187.     ip_info_t *info;
  188.  
  189.     (void) len;
  190.     ASSERT (validate_connection (con));
  191.  
  192.     if (ISUSER (con))
  193.     {
  194.         send_cmd (con, MSG_SERVER_NOSUCH, "you are already logged in");
  195.         return;
  196.     }
  197.  
  198.     ac = split_line (av, FIELDS (av), pkt);
  199.  
  200.     /* check for the correct number of fields for this message type.  some
  201.        clients send extra fields, so we just check to make sure we have
  202.        enough for what is required in this implementation. */
  203.     if (ISUNKNOWN (con))
  204.     {
  205.         if (ac < 5)
  206.         {
  207.             log ("login: too few parameters (tag=%d)", tag);
  208.             print_args (ac, av);
  209.             if (ISUNKNOWN (con))
  210.             {
  211.                 unparsable (con);
  212.                 destroy_connection (con);
  213.             }
  214.             return;
  215.         }
  216.         host = con->host;
  217.         ip = con->ip;
  218.         Connection_Count++;     /* local client connections */
  219.     }
  220.     else
  221.     {
  222.         ASSERT (ISSERVER (con));
  223.         if (ac < 10)
  224.         {
  225.             log ("login: too few parameters from server %s", con->host);
  226.             if (ac > 0)
  227.             {
  228.                 /* send a kill back to this server so we stay synched. */
  229.                 kill_client (con, av[0], "bad login message from server");
  230.  
  231.                 /* this could be misleading since we haven't yet checked if
  232.                  * this user is already logged in via this or another server.
  233.                  * so it could look like we have killed the existing users.
  234.                  * however, this shouldn't happen very often since no other
  235.                  * OpenNap software exists at the moment.
  236.                  */
  237.             }
  238.             return;
  239.         }
  240.         ip = strtoul (av[7], 0, 10);
  241.         strncpy (realhost, my_ntoa (BSWAP32 (ip)), sizeof (realhost));
  242.         realhost[sizeof (realhost) - 1] = 0;
  243.         host = realhost;
  244.     }
  245.  
  246.     /* find info on this host */
  247.     info = hash_lookup (Clones, (void *) ip);
  248.     if (!info)
  249.     {
  250.         info = CALLOC (1, sizeof (ip_info_t));
  251.         info->ip = ip;
  252.         hash_add (Clones, (void *) ip, info);
  253.     }
  254.  
  255.     /* check for clients that are either reconnecting too fast */
  256.     if (ISUNKNOWN (con) && Login_Interval > 0 &&
  257.             (global.current_time - info->last_connect < Login_Interval))
  258.     {
  259.         /* client is reconnecting too fast */
  260.         log ("login: %s is reconnecting too fast", my_ntoa (BSWAP32 (ip)));
  261.         send_cmd (con, MSG_SERVER_ERROR, "reconnecting too fast");
  262.         destroy_connection (con);
  263.         return;
  264.     }
  265.  
  266.     /* update connection timer */
  267.     info->last_connect = global.current_time;
  268.     info->connects++;
  269.  
  270.     clientinfo = hashlist_add (Client_Versions, av[3], 0);
  271.  
  272.     if (invalid_nick (av[0]))
  273.     {
  274.         if (ISUNKNOWN (con))
  275.         {
  276.             send_cmd (con, MSG_SERVER_BAD_NICK, "");
  277.             destroy_connection (con);
  278.         }
  279.         else
  280.         {
  281.             ASSERT (ISSERVER (con));
  282.             kill_client (con, av[0], "invalid nick");
  283.         }
  284.         return;
  285.     }
  286.  
  287.     /* retrieve registration info (could be NULL) */
  288.     db = hash_lookup (User_Db, av[0]);
  289.  
  290. #if ROUTING_ONLY
  291.     /* if running as a hub-only, only accept local client logins from
  292.      * admin+ level users.  we never allow anyone else to log in.
  293.      */
  294.     if (ISUNKNOWN (con) && (!db || db->level < LEVEL_ADMIN))
  295.     {
  296.         log ("login: rejected login from %s!%s (not admin+)", av[0],
  297.              con->host);
  298.         destroy_connection (con);
  299.         return;
  300.     }
  301. #endif
  302.  
  303.     /* bypass restrictions for privileged users */
  304.     if (!db || db->level < LEVEL_MODERATOR)
  305.     {
  306.         int clone_count;
  307.         /* check for user!ip ban.  */
  308.         if (check_ban (con, av[0], host))
  309.             return;
  310.  
  311.         /* check for max clones (global).  use >= for comparison since we 
  312.          * are not counting the current connection
  313.          */
  314.         if ((clone_count = check_class (con, info)))
  315.         {
  316.             log ("login: clones detected from %s [%d]",
  317.                     my_ntoa (BSWAP32 (ip)), clone_count);
  318.             if (ISUNKNOWN (con))
  319.             {
  320.                 send_cmd (con, MSG_SERVER_ERROR,
  321.                           "Exceeded maximum connections");
  322.                 notify_mods (BANLOG_MODE, "Clones detected from %s [%d]",
  323.                              my_ntoa (BSWAP32 (ip)), clone_count);
  324.                 destroy_connection (con);
  325.             }
  326.             else
  327.             {
  328.                 kill_client (con, av[0], "Exceeded maximum connections");
  329.             }
  330.             return;
  331.         }
  332.  
  333.         if (ISUNKNOWN (con))
  334.         {
  335.             /* enforce maximum local users */
  336.             if (global.clients_num >= Max_Connections)
  337.             {
  338.                 /* check if another client can be ejected */
  339.                 if (!option (ON_EJECT_WHEN_FULL) || !eject_client (con))
  340.                 {
  341.                     log ("login: max_connections (%d) reached",
  342.                          Max_Connections);
  343.                     send_cmd (con, MSG_SERVER_ERROR,
  344.                               "This server is full (%d connections)",
  345.                               Max_Connections);
  346.                     destroy_connection (con);
  347.                     return;
  348.                 }
  349.             }
  350.         }
  351.     }
  352.  
  353.     speed = atoi (av[4]);
  354.     if (speed < 0 || speed > 10)
  355.     {
  356.         if (ISUNKNOWN (con))
  357.         {
  358.             send_cmd (con, MSG_SERVER_ERROR, "%s: invalid speed", av[4]);
  359.             destroy_connection (con);
  360.             return;
  361.         }
  362.         ASSERT (ISSERVER (con));
  363.         notify_mods (ERROR_MODE,
  364.                      "Invalid speed %d for user %s from server %s", speed,
  365.                      av[0], con->host);
  366.         log ("login: invalid speed %d received from server %s", speed,
  367.              con->host);
  368.         /* set to something sane.  this is only informational so its not
  369.            a big deal if we are out of synch */
  370.         speed = 0;
  371.     }
  372.  
  373.     port = atoi (av[2]);
  374.  
  375.     if (port < 0 || port > 65535)
  376.     {
  377.         if (ISUNKNOWN (con))
  378.         {
  379.             send_cmd (con, MSG_SERVER_ERROR, "%s: invalid port", av[2]);
  380.             destroy_connection (con);
  381.             return;
  382.         }
  383.         ASSERT (ISSERVER (con));
  384.         notify_mods (ERROR_MODE, "Invalid port %d for user %s from server %s",
  385.                      port, av[0], con->host);
  386.         log ("login: invalid port %d received from server %s",
  387.              port, con->host);
  388.         port = 0;
  389.         /* TODO: generate a change port command */
  390.     }
  391.  
  392.     if (tag == MSG_CLIENT_LOGIN && db == NULL)
  393.     {
  394.         if (option (ON_REGISTERED_ONLY))
  395.         {
  396.             send_cmd (con, MSG_SERVER_ERROR,
  397.                     "only registered accounts allowed on this server");
  398.             destroy_connection (con);
  399.             return;
  400.         }
  401.         /* the requested nick is not registered.  if we are supposed to
  402.          * automatically register all new accounts, switch the command type
  403.          * here to simulate MSG_CLIENT_LOGIN_REGISTER (6).
  404.          */
  405.         if (option (ON_AUTO_REGISTER))
  406.             tag = MSG_CLIENT_LOGIN_REGISTER;
  407.     }
  408.  
  409.     if (tag == MSG_CLIENT_LOGIN_REGISTER)
  410.     {
  411.         if (option (ON_RESTRICT_REGISTRATION))
  412.         {
  413.             send_cmd (con, MSG_SERVER_ERROR, "This is a restricted server");
  414.             return;
  415.         }
  416.  
  417.         /* check to see if the account is already registered */
  418.         if (db)
  419.         {
  420.             if (ISUNKNOWN (con))
  421.             {
  422.                 /* this could happen if two clients simultaneously connect
  423.                    and register */
  424.                 send_cmd (con, MSG_SERVER_ERROR,
  425.                           "Nick registered to another user");
  426.                 destroy_connection (con);
  427.             }
  428.             else
  429.             {
  430.                 ASSERT (ISSERVER (con));
  431.                 /* need to issue a kill and send the registration info
  432.                    we have on this server */
  433.                 kill_client (con, av[0], "Nick registered to another user");
  434.                 sync_reginfo (db);
  435.             }
  436.             return;
  437.         }
  438.         /* else, delay creating db until after we make sure the nick is
  439.            not currently in use */
  440.     }
  441.     else if (db)
  442.     {
  443.         ASSERT (tag == MSG_CLIENT_LOGIN);
  444.         /* check the user's password */
  445.         if (check_pass (db->password, av[1]))
  446.         {
  447.             log ("login: bad password for %s (%s) from %s",
  448.                  db->nick, Levels[db->level], host);
  449.  
  450.             if (ISUNKNOWN (con))
  451.             {
  452.                 send_cmd (con, MSG_SERVER_ERROR, "Invalid Password");
  453.                 destroy_connection (con);
  454.             }
  455.             else
  456.             {
  457.                 ASSERT (ISSERVER (con));
  458.                 /* if another server let this message pass through, that
  459.                    means they probably have an out of date password.  notify
  460.                    our peers of the registration info.  note that it could be
  461.                    _this_ server that is stale, but when the other servers
  462.                    receive this message they will check the creation date and
  463.                    send back any entries which are more current that this one.
  464.                    kind of icky, but its the best we can do */
  465.                 kill_client (con, av[0], "Invalid Password");
  466.                 sync_reginfo (db);
  467.             }
  468.             return;
  469.         }
  470.     }
  471.  
  472.     /* check to make sure that this user isn't ready logged in. */
  473.     if ((user = hash_lookup (Users, av[0])))
  474.     {
  475.         ASSERT (validate_user (user));
  476.  
  477.         if (ISUNKNOWN (con))
  478.         {
  479.             /* check for ghosts.  if another client from the same ip address
  480.                logs in, kill the older client and proceed normally */
  481.             if (!option (ON_GHOST_KILL) || user->ip != con->ip)
  482.             {
  483.                 send_cmd (con, MSG_SERVER_ERROR, "%s is already active",
  484.                           user->nick);
  485.                 destroy_connection (con);
  486.                 return;
  487.             }
  488.  
  489.             /* pass the kill message to all servers */
  490.             pass_message_args (NULL, MSG_CLIENT_KILL,
  491.                     ":%s %s \"ghost (%s)\"",
  492.                     Server_Name, user->nick, user->server);
  493.             notify_mods (KILLLOG_MODE, "Server %s killed %s: ghost (%s)",
  494.                     Server_Name, user->nick, user->server);
  495.             /* remove the old entry */
  496.             if (ISUSER (user->con))
  497.             {
  498.                 send_cmd (user->con, MSG_SERVER_GHOST, "");
  499.                 zap_local_user (user->con,
  500.                         "Someone else is logging in as you, disconnecting.");
  501.             }
  502.             else
  503.                 hash_remove (Users, user->nick);
  504.         }
  505.         else
  506.         {
  507.             ASSERT (ISSERVER (con));
  508.             /* check the timestamp to see which client is older.  the last
  509.              * one to connect gets killed.
  510.              */
  511.             if (atoi (av[6]) < user->connected)
  512.             {
  513.                 /* reject the client that was already logged in since has
  514.                    an older timestamp */
  515.  
  516.                 /* the user we see logged in after the same user on another
  517.                    server, so we want to kill the existing user.  we don't
  518.                    pass this back to the server that we received the login
  519.                    from because that will kill the legitimate user */
  520.                 pass_message_args (con, MSG_CLIENT_KILL,
  521.                                    ":%s %s \"nick collision (%s %s)\"",
  522.                                    Server_Name, user->nick, av[8],
  523.                                    user->server);
  524.                 notify_mods (KILLLOG_MODE,
  525.                              "Server %s killed %s: nick collision (%s %s)",
  526.                              Server_Name, user->nick, av[8], user->server);
  527.  
  528.                 if (ISUSER (user->con))
  529.                     zap_local_user (user->con, "nick collision");
  530.                 else
  531.                     hash_remove (Users, user->nick);
  532.                 /* proceed with login normally */
  533.             }
  534.             else
  535.             {
  536.                 /* the client we already know about is older, reject
  537.                  * this login
  538.                  */
  539.                 log
  540.                     ("login: nick collision for user %s, rejected login from server %s",
  541.                      user->nick, con->host);
  542. #if 0
  543.                 send_cmd (con, MSG_CLIENT_KILL, ":%s %s \"nick collision\"",
  544.                           Server_Name, user->nick);
  545. #endif
  546.                 return;
  547.             }
  548.         }
  549.     }
  550.  
  551.     if (tag == MSG_CLIENT_LOGIN_REGISTER)
  552.     {
  553.         /* check to make sure the client isn't registering nicknames too
  554.          * fast.
  555.          */
  556.         if (Register_Interval > 0 &&
  557.                 (global.current_time - info->last_register < Register_Interval))
  558.         {
  559.             /* client is attempting to register nicks too fast */
  560.             log ("login: %s is registering nicks too fast",
  561.                     my_ntoa (BSWAP32 (ip)));
  562.             send_cmd (con, MSG_SERVER_ERROR, "reregistering too fast");
  563.             destroy_connection (con);
  564.             return;
  565.         }
  566.  
  567.         /* create the registration entry now */
  568.         ASSERT (db == 0);
  569.         db = CALLOC (1, sizeof (USERDB));
  570.         if (db)
  571.         {
  572.             db->nick = STRDUP (av[0]);
  573.             db->password = generate_pass (av[1]);
  574. #if EMAIL
  575.             if (ac > 5)
  576.                 db->email = STRDUP (av[5]);
  577.             else
  578.             {
  579.                 snprintf (Buf, sizeof (Buf), "anon@%s", Server_Name);
  580.                 db->email = STRDUP (Buf);
  581.             }
  582. #endif
  583.         }
  584.         if (!db || !db->nick || !db->password
  585. #if EMAIL
  586.             || !db->email
  587. #endif
  588.             )
  589.         {
  590.             OUTOFMEMORY ("login");
  591.             if (con->class == CLASS_UNKNOWN)
  592.                 destroy_connection (con);
  593.             userdb_free (db);
  594.             return;
  595.         }
  596.         db->level = LEVEL_USER;
  597.         db->created = global.current_time;
  598.         db->lastSeen = global.current_time;
  599.         if (hash_add (User_Db, db->nick, db))
  600.         {
  601.             log ("login: hash_add failed (ignored)");
  602.             userdb_free (db);
  603.             db = NULL;
  604.         }
  605.  
  606.         /* update the timer for registration.  we wait until here so that
  607.          * attempts to register existing nicks don't count against the client.
  608.          * this timer is only to prevent a client from successfully
  609.          * registering nicks too quickly.
  610.          */
  611.         info->last_register = global.current_time;
  612.     }
  613.  
  614.     user = CALLOC (1, sizeof (USER));
  615.     if (user)
  616.     {
  617. #if DEBUG
  618.         user->magic = MAGIC_USER;
  619. #endif
  620.         user->nick = STRDUP (av[0]);
  621.         /* if the client version string is too long, truncate it */
  622.         if (Max_Client_String > 0
  623.             && strlen (av[3]) > (unsigned) Max_Client_String)
  624.             *(av[3] + Max_Client_String) = 0;
  625.         user->clientinfo = clientinfo->key;
  626.         user->pass = STRDUP (av[1]);
  627.     }
  628.     if (!user || !user->nick || !user->pass)
  629.     {
  630.         OUTOFMEMORY ("login");
  631.         goto failed;
  632.     }
  633.     user->port = port;
  634.     user->speed = speed;
  635.     user->con = con;
  636.     user->level = LEVEL_USER;   /* default */
  637.     user->ip = ip;
  638.  
  639.     /* if this is a locally connected user, update our information */
  640.     if (ISUNKNOWN (con))
  641.     {
  642.         /* save the ip address of this client */
  643.         user->connected = global.current_time;
  644.         user->local = 1;
  645.         user->conport = con->port;
  646.         user->server = Server_Name;     /* NOTE: this is not malloc'd */
  647.         con->uopt = CALLOC (1, sizeof (USEROPT));
  648.         if (!con->uopt)
  649.         {
  650.             OUTOFMEMORY ("login");
  651.             goto failed;
  652.         }
  653.         con->uopt->usermode = /*LOGALL_MODE */ UserMode_int;
  654.         con->user = user;
  655.         con->class = CLASS_USER;
  656.         /* send the login ack */
  657. #if EMAIL
  658.         if (db)
  659.             send_cmd (con, MSG_SERVER_EMAIL, "%s", db->email);
  660.         else
  661. #endif
  662.             send_cmd (con, MSG_SERVER_EMAIL, "anon@%s", Server_Name);
  663.         show_motd (con, 0, 0, NULL);
  664.         server_stats (con, 0, 0, NULL);
  665.     }
  666.     else
  667.     {
  668.         ASSERT (ISSERVER (con));
  669.         user->connected = atoi (av[6]);
  670.         user->server = find_server (av[8]);     /* just a ref, not malloc'd */
  671.         user->conport = atoi (av[9]);
  672.     }
  673.  
  674.     if (hash_add (Users, user->nick, user))
  675.     {
  676.         log ("login(): hash_add failed (fatal)");
  677.         goto failed;
  678.     }
  679.  
  680.     /* keep track of the number of clients from each unique ip address.  we
  681.      * use this to detect clones globally.
  682.      */
  683.     info->users++;
  684.  
  685.     /* pass this information to our peer servers */
  686.     pass_message_args (con, MSG_CLIENT_LOGIN,
  687.                        "%s %s %s \"%s\" %s %s %u %u %s %hu",
  688.                        user->nick, av[1], av[2], av[3], av[4],
  689. #if EMAIL
  690.                        db ? db->email : "unknown",
  691. #else
  692.                        "unknown",
  693. #endif /* EMAIL */
  694.                        user->connected, user->ip, user->server,
  695.                        user->conport);
  696.  
  697.     if (db)
  698.     {
  699.         db->lastSeen = global.current_time;
  700.  
  701.         /* this must come after the email ack or the win client gets confused */
  702.         if (db->level != LEVEL_USER)
  703.         {
  704.             /* do this before setting the user level so this user is not
  705.                notified twice */
  706.             notify_mods (LEVELLOG_MODE,
  707.                          "Server %s set %s's user level to %s (%d)",
  708.                          Server_Name, user->nick, Levels[db->level],
  709.                          db->level);
  710.             user->level = db->level;
  711.             if (ISUSER (con))
  712.             {
  713.                 /* notify users of their change in level */
  714.                 send_cmd (con, MSG_SERVER_NOSUCH,
  715.                           "Server %s set your user level to %s (%d).",
  716.                           Server_Name, Levels[user->level], user->level);
  717.                 if (user->level >= LEVEL_MODERATOR)
  718.                 {
  719.                     LIST   *list = CALLOC (1, sizeof (LIST));
  720.  
  721.                     list->data = con;
  722.                     Mods = list_push (Mods, list);
  723.                 }
  724.             }
  725.             /* ensure all servers are synched up.  use the timestamp here
  726.                so that multiple servers all end up with the same value if
  727.                they differ */
  728.             pass_message_args (NULL, MSG_CLIENT_SETUSERLEVEL, ":%s %s %s",
  729.                                Server_Name, user->nick, Levels[user->level]);
  730.         }
  731.  
  732.         if (db->flags & ON_MUZZLED)
  733.         {
  734.             /* user was muzzled when they quit, remuzzle */
  735.             user->muzzled = 1;
  736.             /* this will result in duplicate messages for the same user from
  737.                each server, but its the only way to guarantee that the user
  738.                is muzzled upon login */
  739.             pass_message_args (NULL, MSG_CLIENT_MUZZLE,
  740.                                ":%s %s \"quit while muzzled\"",
  741.                                Server_Name, user->nick);
  742.             if (ISUSER (con))
  743.                 send_cmd (con, MSG_SERVER_NOSUCH,
  744.                           "You have been muzzled by server %s: quit while muzzled",
  745.                           Server_Name);
  746.             notify_mods (MUZZLELOG_MODE,
  747.                          "Server %s has muzzled %s: quit while muzzled",
  748.                          Server_Name, user->nick);
  749.         }
  750.     }
  751.  
  752.     /* check the global hotlist to see if there are any users waiting to be
  753.        informed of this user signing on */
  754.     for (list = hashlist_lookup (Hotlist, user->nick); list;
  755.          list = list->next)
  756.     {
  757.         ASSERT (validate_connection (list->data));
  758.         send_cmd (list->data, MSG_SERVER_USER_SIGNON, "%s %d",
  759.                   user->nick, user->speed);
  760.     }
  761.  
  762.     return;
  763.  
  764.   failed:
  765.     /* clean up anything we allocated here */
  766.     if (!ISSERVER (con))
  767.         destroy_connection (con);
  768.     if (user)
  769.     {
  770.         if (user->nick)
  771.             FREE (user->nick);
  772.         if (user->pass)
  773.             FREE (user->pass);
  774.         if (user->server)
  775.             FREE (user->server);
  776.         FREE (user);
  777.     }
  778. }
  779.  
  780. /* check to see if a nick is already registered */
  781. /* 7 <nick> */
  782. HANDLER (register_nick)
  783. {
  784.     USERDB *db;
  785.  
  786.     (void) tag;
  787.     (void) len;
  788.     ASSERT (validate_connection (con));
  789.     if (con->class != CLASS_UNKNOWN)
  790.     {
  791.         log ("register_nick(): command received after registration");
  792.         send_cmd (con, MSG_SERVER_NOSUCH, "You are already logged in.");
  793.         return;
  794.     }
  795.     if ((db = hash_lookup (User_Db, pkt)))
  796.     {
  797.         send_cmd (con, MSG_SERVER_REGISTER_FAIL, "");
  798.         return;
  799.     }
  800.     if (invalid_nick (pkt))
  801.         send_cmd (con, MSG_SERVER_BAD_NICK, "");
  802.     else
  803.         send_cmd (con, MSG_SERVER_REGISTER_OK, "");
  804. }
  805.  
  806. /* 10114 :<server> <nick> <password> <level> <email> <created> */
  807. HANDLER (reginfo)
  808. {
  809.     char   *server;
  810.     char   *fields[6];
  811.     USERDB *db;
  812.     int     level;
  813.     int     ac = -1;
  814.  
  815.     (void) tag;
  816.     (void) len;
  817.     ASSERT (validate_connection (con));
  818.     CHECK_SERVER_CLASS ("reginfo");
  819.  
  820.     if (*pkt != ':')
  821.     {
  822.         log ("reginfo: message does not begin with :");
  823.         return;
  824.     }
  825.     pkt++;
  826.     server = next_arg (&pkt);
  827.     if (pkt)
  828.         ac = split_line (fields, sizeof (fields) / sizeof (char *), pkt);
  829.  
  830.     if (ac < 5)
  831.     {
  832.         log ("reginfo: wrong number of fields");
  833.         return;
  834.     }
  835.     /* look up any entry we have for this user */
  836.     db = hash_lookup (User_Db, pkt);
  837.     if (db)
  838.     {
  839.         /* check the timestamp to see if this is more recent than what
  840.          * we have
  841.          */
  842.         if (atol (fields[4]) > db->created)
  843.         {
  844.             /* our record was created first, notify peers */
  845.             log ("reginfo: stale reginfo received from %s", server);
  846.             sync_reginfo (db);
  847.             return;
  848.         }
  849.         /* update our record */
  850.         FREE (db->password);
  851. #if EMAIL
  852.         FREE (db->email);
  853. #endif
  854.     }
  855.     else
  856.     {
  857.         if (invalid_nick (fields[0]))
  858.         {
  859.             log ("reginfo: received invalid nickname");
  860.             return;
  861.         }
  862.         db = CALLOC (1, sizeof (USERDB));
  863.         if (db)
  864.             db->nick = STRDUP (fields[0]);
  865.         if (!db || !db->nick)
  866.         {
  867.             OUTOFMEMORY ("reginfo");
  868.             if (db)
  869.                 FREE (db);
  870.             return;
  871.         }
  872.         hash_add (User_Db, db->nick, db);
  873.     }
  874.     level = get_level (fields[3]);
  875.     if (level == -1)
  876.     {
  877.         log ("reginfo: invalid level %s", fields[3]);
  878.         level = LEVEL_USER;     /* reset to something reasonable */
  879.     }
  880.  
  881.     pass_message_args (con, tag, ":%s %s %s %s %s %s %s",
  882.                        server, fields[0], fields[1], fields[2], Levels[level],
  883.                        fields[4], (ac > 5) ? fields[5] : "0");
  884.  
  885.     /* this is already the MD5-hashed password, just copy it */
  886.     db->password = STRDUP (fields[1]);
  887. #if EMAIL
  888.     db->email = STRDUP (fields[2]);
  889. #endif
  890.     if (!db->password
  891. #if EMAIL
  892.         || !db->email
  893. #endif
  894.         )
  895.     {
  896.         OUTOFMEMORY ("reginfo");
  897.         return;
  898.     }
  899.     db->level = level;
  900.     db->created = atol (fields[4]);
  901. }
  902.  
  903. /* 10200 [ :<sender> ] <user> <pass> <email> [ <level> ]
  904.    admin command to force registration of a nickname */
  905. HANDLER (register_user)
  906. {
  907.     USER   *sender;
  908.     int     ac = -1, level;
  909.     char   *av[4];
  910.     char   *sender_name;
  911.     USERDB *db;
  912.  
  913.     (void) len;
  914.     ASSERT (validate_connection (con));
  915.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  916.         return;
  917.     if (sender && sender->level < LEVEL_ADMIN)
  918.     {
  919.         permission_denied (con);
  920.         return;
  921.     }
  922.     if (pkt)
  923.         ac = split_line (av, FIELDS (av), pkt);
  924.     if (ac < 3)
  925.     {
  926.         unparsable (con);
  927.         return;
  928.     }
  929.     if (invalid_nick (av[0]))
  930.     {
  931.         invalid_nick_msg (con);
  932.         return;
  933.     }
  934.     /* if the user level was specified do some security checks */
  935.     if (ac > 3)
  936.     {
  937.         level = get_level (av[3]);
  938.         /* check for a valid level */
  939.         if (level == -1)
  940.         {
  941.             if (ISUSER (con))
  942.                 send_cmd (con, MSG_SERVER_NOSUCH, "Invalid level");
  943.             return;
  944.         }
  945.         /* check that the user has permission to create a user of this level */
  946.         if (sender && sender->level < LEVEL_ELITE && level >= sender->level)
  947.         {
  948.             permission_denied (con);
  949.             return;
  950.         }
  951.     }
  952.     else
  953.         level = LEVEL_USER;     /* default */
  954.  
  955.     /* first check to make sure this user is not already registered */
  956.     if (hash_lookup (User_Db, av[0]))
  957.     {
  958.         if (sender)
  959.             send_user (sender, MSG_SERVER_NOSUCH,
  960.                        "[%s] %s is already registered", Server_Name, av[0]);
  961.         return;
  962.     }
  963.  
  964.     /* pass the plain text password here */
  965.     pass_message_args (con, tag, ":%s %s %s %s %s",
  966.                        sender_name, av[0], av[1], av[2], ac > 3 ? av[3] : "");
  967.  
  968.     db = CALLOC (1, sizeof (USERDB));
  969.     if (!db)
  970.     {
  971.         OUTOFMEMORY ("register_user");
  972.         return;
  973.     }
  974.     db->nick = STRDUP (av[0]);
  975.     db->password = generate_pass (av[1]);
  976. #if EMAIL
  977.     db->email = STRDUP (av[2]);
  978. #endif
  979.     if (!db->nick || !db->password
  980. #if EMAIL
  981.         || !db->email
  982. #endif
  983.         )
  984.     {
  985.         OUTOFMEMORY ("register_user");
  986.         FREE (db);
  987.         return;
  988.     }
  989.     db->level = level;
  990.     db->created = global.current_time;
  991.     db->lastSeen = global.current_time;
  992.     hash_add (User_Db, db->nick, db);
  993.  
  994.     notify_mods (CHANGELOG_MODE, "%s registered nickname %s (%s)",
  995.                  sender_name, db->nick, Levels[db->level]);
  996. }
  997.  
  998. /* 11 <user> <password>
  999.    check password */
  1000. HANDLER (check_password)
  1001. {
  1002.     char   *nick;
  1003.     USERDB *db;
  1004.  
  1005.     (void) tag;
  1006.     (void) len;
  1007.     ASSERT (validate_connection (con));
  1008.     ASSERT (con->class == CLASS_UNKNOWN);
  1009.     nick = next_arg (&pkt);
  1010.     if (!nick)
  1011.     {
  1012.         unparsable (con);
  1013.         return;
  1014.     }
  1015.     if (!pkt)
  1016.     {
  1017.         send_cmd (con, MSG_SERVER_NOSUCH,
  1018.                   "check password failed: missing password");
  1019.         return;
  1020.     }
  1021.     db = hash_lookup (User_Db, nick);
  1022.     if (db)
  1023.     {
  1024.         if (!check_pass (db->password, pkt))
  1025.             send_cmd (con, MSG_SERVER_PASS_OK, "");
  1026.     }
  1027. }
  1028.  
  1029. /* stub handler for numerics we just ignore */
  1030. HANDLER (ignore_command)
  1031. {
  1032.     ASSERT (validate_connection (con));
  1033.     (void) tag;
  1034.     (void) len;
  1035.     (void) pkt;
  1036.     (void) con;
  1037.     /* just ignore this message for now */
  1038. #if 0
  1039.     log ("ignore_command: (client=%s) tag=%d, len=%d, data=%s",
  1040.          ISUSER (con) ? con->user->clientinfo : "(unknown)", tag, len, pkt);
  1041. #endif
  1042. }
  1043.  
  1044. void
  1045. ip_info_free (ip_info_t *info)
  1046. {
  1047.     FREE (info);
  1048. }
  1049.  
  1050. static void
  1051. cleanup_ip_info_cb (ip_info_t *info, void *unused)
  1052. {
  1053.     (void) unused;
  1054.     if (info->users == 0 &&
  1055.             (global.current_time - info->last_connect > Login_Interval) &&
  1056.             (global.current_time - info->last_register > Register_Interval))
  1057.         hash_remove (Clones, (void *) info->ip);
  1058. }
  1059.  
  1060. /* this function is periodically called to remove stale info from the
  1061.  * clone table.  if there are no users from this ip logged in and the
  1062.  * last connect is older than minimum allowed, we can safely remove the
  1063.  * entry from the list
  1064.  */
  1065. void
  1066. cleanup_ip_info (void)
  1067. {
  1068.     hash_foreach (Clones, (hash_callback_t) cleanup_ip_info_cb, NULL);
  1069.     log ("cleanup_ip_info: %d addresses in the table", Clones->dbsize);
  1070. }
  1071.